package service

import (
	"errors"
	"fmt"
	"strings"

	"gitee.com/sansaniot/ssiot-core/httpmvc/service"
	"gorm.io/gorm"

	"ssdevice/common/constant"
	cDto "ssdevice/common/dto"
	"ssdevice/internal/device/models"
	"ssdevice/internal/device/models/command"
	"ssdevice/internal/device/models/query"
)

type ProductVariable struct {
	productModel   *models.SysDevProduct
	devSchemaModel *models.SysDevSchema
	devConfigModel *models.SysDevConfig
	variableModel  *models.SysProductVariable
	service.Service
}

func (d *ProductVariable) SetProductModel(m *models.SysDevProduct) *ProductVariable {
	d.productModel = m
	return d
}

func (d *ProductVariable) SetSchemaModel(m *models.SysDevSchema) *ProductVariable {
	d.devSchemaModel = m
	return d
}

func (d *ProductVariable) SetConfigModel(m *models.SysDevConfig) *ProductVariable {
	d.devConfigModel = m
	return d
}

func (d *ProductVariable) SetVariableModel(m *models.SysProductVariable) *ProductVariable {
	d.variableModel = m
	return d
}

func (d *ProductVariable) SetAllModel() {
	d.productModel = &models.SysDevProduct{}
	d.devSchemaModel = &models.SysDevSchema{}
	d.devConfigModel = &models.SysDevConfig{}
	d.variableModel = &models.SysProductVariable{}
	d.productModel.Orm = d.Orm
	d.devSchemaModel.Orm = d.Orm
	d.devConfigModel.Orm = d.Orm
	d.variableModel.Orm = d.Orm
}

// 添加变量
func (d *ProductVariable) UpsertVariable(req *command.ProdVariableInsertReq) (err error, productVariable models.SysProductVariable) {
	sysDevProduct := models.SysDevProduct{}
	if err = d.productModel.FindOne(&sysDevProduct, cDto.MakeCondition(query.SysProductQuery{ProductModel: req.ProductModel})); err != nil {
		return
	}
	if sysDevProduct.DeptId == constant.PublicGroupId && req.UserId != "1" {
		err = errors.New("没权限操作公共分组资源")
		return
	}
	req.Generate(&productVariable)
	if err = d.Orm.Transaction(func(tx *gorm.DB) error {
		// 事务orm
		d.variableModel.Orm = tx
		// 添加变量
		if err = d.variableModel.Upsert(&productVariable, []string{"product_model", "key"}...); err != nil {
			return err
		}
		// 更新设备schema
		if err = prodVariableSchema(tx, productVariable); err != nil {
			return err
		}
		// 更新设备config
		if err = prodVariableProfile(tx, productVariable); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return
	}
	return
}

// 删除变量
func (d *ProductVariable) DeleteVariable(req *command.ProdVariableDeleteReq) (err error) {
	if len(req.ModelKey) == 0 {
		return
	}
	err = d.Orm.Transaction(func(tx *gorm.DB) error {
		// 事务orm
		d.variableModel.Orm = tx
		// 批量操作
		for pdmodel, keys := range req.ModelKey {
			sysDevProduct := models.SysDevProduct{}
			_ = d.productModel.FindOne(&sysDevProduct, cDto.MakeCondition(query.SysProductQuery{ProductModel: pdmodel}))
			if sysDevProduct.DeptId == constant.PublicGroupId && req.UserId != "1" {
				return errors.New("没权限操作公共分组资源")
			}
			// 变量表
			if err = d.variableModel.Delete(d.variableModel, cDto.MakeCondition(query.SysProductVariableQuery{ProductModel: pdmodel, KeyIn: keys})); err != nil {
				return err
			}
			for _, key := range keys {
				// profile
				jsonPath := fmt.Sprintf("{config,sensor,%s}", strings.ReplaceAll(key, ".", ","))
				sql := "update sys_dev_config set data = jsonb_delete_path(data::jsonb, '" + jsonPath + "') where product_model = '%s'"
				sql = fmt.Sprintf(sql, pdmodel)
				if err = tx.Raw(sql).Scan(d.devConfigModel).Error; err != nil {
					return err
				}
				// schema (.变成 .properties. )
				kk := strings.ReplaceAll(key, ".", ",properties,")
				jsonPath = fmt.Sprintf("{properties,sensor,properties,%s}", kk)
				sql = "update sys_dev_schema set schema = jsonb_delete_path(schema::jsonb, '" + jsonPath + "') where product_model = '%s'"
				sql = fmt.Sprintf(sql, pdmodel)
				if err = tx.Raw(sql).Scan(d.devSchemaModel).Error; err != nil {
					return err
				}
				// schema config
				jsonPath = fmt.Sprintf("{properties,config,properties,sensor,properties,%s}", kk)
				sql = "update sys_dev_schema set schema = jsonb_delete_path(schema::jsonb, '" + jsonPath + "') where product_model = '%s'"
				sql = fmt.Sprintf(sql, pdmodel)
				if err = tx.Raw(sql).Scan(d.devSchemaModel).Error; err != nil {
					return err
				}
			}
		}
		return nil
	})
	return
}
